# # pandas 教程
# import pandas as pd
#
# # 创建一个简单的 DataFrame
# data = {'Name': ['Google', 'Runoob', 'Taobao'], 'Age': [25, 30, 35]}
# df = pd.DataFrame(data)
#
# # 查看 DataFrame
# print(df)
# print(df.to_string(index=False))
# print(df.columns) # 使用 columns 属性查看列索引
# print(f"列名: {list(df.columns)}")
#
#
#
# # pandas 简介
# # DataFrame 是一个表格型的数据结构，它含有一组有序的列，每列可以是不同的值类型（数值、字符串、布尔型值）。
# # DataFrame 既有行索引也有列索引，它可以被看做由 Series 组成的字典（共同用一个索引）。
# import pandas as pd
#
# # 创建两个Series对象
# series_apples = pd.Series([1, 3, 7, 4])
# series_bananas = pd.Series([2, 6, 3, 5])
#
# # 将两个Series对象相加，得到DataFrame，并指定列名
# df = pd.DataFrame({ 'Apples': series_apples, 'Bananas': series_bananas })
#
# # 显示DataFrame
# print(df.to_string(index=False))
# print(df['Apples'].to_string(index= False))
# print(list(df.columns))
#
# # pandas 安装
# import pandas
# print(pandas.__version__)# 查看版本
#
# import pandas as pd
# mydataset = {
#   'sites': ["Google", "Runoob", "Wiki"],
#   'number': [1, 2, 3]
# }
# myvar = pd.DataFrame(mydataset)
# print(myvar)

# Pandas 数据结构 - Series
# 一维数组、索引、数据类型、大小不变性、操作、缺失数据、自动对齐、、

import pandas as pd

# 创建一个Series对象，指定名称为'A'，值分别为1, 2, 3, 4
# 默认索引为0, 1, 2, 3
series = pd.Series([1, 2, 3, 4], name='A')

# 显示Series对象
print(series)

# 如果你想要显式地设置索引，可以这样做：
custom_index = [1, 2, 3, 4]  # 自定义索引
series_with_index = pd.Series([1, 2, 3, 4], index=custom_index, name='A')

# 显示带有自定义索引的Series对象
print(series_with_index)

# 索引，name,vallue
# pandas.Series(data=None, index=None, dtype=None, name=None, copy=False, fastpath=False)

import pandas as pd
a = [1, 2, 3]
myvar = pd.Series(a)
print(myvar)
print(myvar[1])



# 指定索引值
import pandas as pd
a = ["Google", "Runoob", "Wiki"]
myvar = pd.Series(a, index = ["x", "y", "z"])
print(myvar)
print(myvar["y"])  # 根据索引值获取数据



# 我们也可以使用 key/value 对象，类似字典来创建 Series：
import pandas as pd
sites = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar = pd.Series(sites)
print(myvar)



# 如果我们只需要字典中的一部分数据，只需要指定需要数据的索引即可
import pandas as pd
sites = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar = pd.Series(sites, index = [1, 2])
print(myvar)


# 设置 Series 名称参数：
import pandas as pd
sites = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar = pd.Series(sites, index = [1, 2], name="RUNOOB-Series-TEST" )
print(myvar)

# pandas.Series(data=None, index=None, dtype=None, name=None, copy=False, fastpath=False)


# 常用方法
#https://www.runoob.com/pandas/pandas-series.html
# index	            获取 Series 的索引
# values	        获取 Series 的数据部分（返回 NumPy 数组）
# head(n)	        返回 Series 的前 n 行（默认为 5）
# tail(n)	        返回 Series 的后 n 行（默认为 5）
# dtype	            返回 Series 中数据的类型
# shape	            返回 Series 的形状（行数）
# describe()	    返回 Series 的统计描述（如均值、标准差、最小值等）
# isnull()	        返回一个布尔 Series，表示每个元素是否为 NaN
# notnull()	        返回一个布尔 Series，表示每个元素是否不是 NaN
# unique()	        返回 Series 中的唯一值（去重）
# value_counts()	返回 Series 中每个唯一值的出现次数
# map(func)	        将指定函数应用于 Series 中的每个元素
# apply(func)	    将指定函数应用于 Series 中的每个元素，常用于自定义操作
# astype(dtype)	    将 Series 转换为指定的类型
# sort_values()	    对 Series 中的元素进行排序（按值排序）
# sort_index()	    对 Series 的索引进行排序
# dropna()	        删除 Series 中的缺失值（NaN）
# fillna(value)	    填充 Series 中的缺失值（NaN）
# replace(to_replace, value)	替换 Series 中指定的值
# cumsum()	        返回 Series 的累计求和
# cumprod()	        返回 Series 的累计乘积
# shift(periods)	将 Series 中的元素按指定的步数进行位移
# rank()	        返回 Series 中元素的排名
# corr(other)	    计算 Series 与另一个 Series 的相关性（皮尔逊相关系数）
# cov(other)	    计算 Series 与另一个 Series 的协方差
# to_list()	        将 Series 转换为 Python 列表
# to_frame()	    将 Series 转换为 DataFrame
# iloc[]	        通过位置索引来选择数据
# loc[]	            通过标签索引来选择数据




import pandas as pd

# 创建 Series
data = [1, 2, 3, 4, 5, 6]
index = ['a', 'b', 'c', 'd', 'e', 'f']
s = pd.Series(data, index=index)

# 查看基本信息
print("索引：", s.index)
print("数据：", s.values)
print("数据类型：", s.dtype)
print("前两行数据：", s.head(2))
print("形状：", s.shape)
print("描述：", s.describe())

# 使用 map 函数将每个元素加倍
s_doubled = s.map(lambda x: x * 2)
print("元素加倍后：", s_doubled)

# 计算累计和
cumsum_s = s.cumsum()
print("累计求和：", cumsum_s)

# 查找缺失值（这里没有缺失值，所以返回的全是 False）
print("缺失值判断：", s.isnull())

# 排序
sorted_s = s.sort_values()
print("排序后的 Series：", sorted_s)


import pandas as pd

# 创建示例数据
data = [10, 20, 30, 40, 50]
index = ['a', 'b', 'c', 'd', 'e']
s = pd.Series(data, index=index)

# 使用 iloc[] 通过位置索引选择数据
print("原始 Series:")
print(s)
print("\n使用 iloc[] 示例:")
print(f"第一个元素: {s.iloc[0]}")        # 选择位置为0的元素
print(f"前三个元素: {s.iloc[:3]}")       # 选择位置0到2的元素
print(f"最后一个元素: {s.iloc[-1]}")     # 选择最后一个元素


import pandas as pd
# 使用相同的数据
data = [10, 20, 30, 40, 50]
index = ['a', 'b', 'c', 'd', 'e']
s = pd.Series(data, index=index)
# 使用 loc[] 通过标签索引选择数据
print("使用 loc[] 示例:")
print(f"标签'a'的元素: {s.loc['a']}")     # 选择标签为'a'的元素
print(f"标签'a'到'c'的元素: {s.loc['a':'c']}")  # 选择标签'a'到'c'的元素
print(f"多个标签: {s.loc[['a', 'd']]}")   # 选择标签'a'和'd'的元素


# ---------------------------
import pandas as np
# 使用列表创建 Series
s = pd.Series([1, 2, 3, 4])
# 使用 NumPy 数组创建 Series
s = pd.Series(np.array([1, 2, 3, 4]))
# 使用字典创建 Series
s = pd.Series({'a': 1, 'b': 2, 'c': 3, 'd': 4})
# 指定索引创建 Series
# s = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])


# 获取值
# value = s[2]  # 获取索引为2的值
print(s['a'])  # 返回索引标签 'a' 对应的元素
# 获取多个值
subset = s[1:4]  # 获取索引为1到3的值
# 使用自定义索引
value = s['b']  # 获取索引为'b'的值

# 索引和值的对应关系
for index, value in s.items():
    print(f"Index: {index}, Value: {value}")

# 使用切片语法来访问 Series 的一部分
print(s['a':'c'])  # 返回索引标签 'a' 到 'c' 之间的元素
print(s[:3])  # 返回前三个元素

# 为特定的索引标签赋值
s['a'] = 10  # 将索引标签 'a' 对应的元素修改为 10
# 通过赋值给新的索引标签来添加元素
s['e'] = 5  # 在 Series 中添加一个新的元素，索引标签为 'e'
# 使用 del 删除指定索引标签的元素。
del s['a']  # 删除索引标签 'a' 对应的元素
# 使用 drop 方法删除一个或多个索引标签，并返回一个新的 Series。
s_dropped = s.drop(['b'])  # 返回一个删除了索引标签 'b' 的新 Series


# 算术运算
result = series * 2  # 所有元素乘以2
# 过滤
filtered_series = series[series > 2]  # 选择大于2的元素

# 数学函数
import numpy as np
result = np.sqrt(series)  # 对每个元素取平方根
print(s.sum())  # 输出 Series 的总和
print(s.mean())  # 输出 Series 的平均值
print(s.max())  # 输出 Series 的最大值
print(s.min())  # 输出 Series 的最小值
print(s.std())  # 输出 Series 的标准差


# 获取索引
index = s.index
# 获取值数组
values = s.values
# 获取描述统计信息
stats = s.describe()
# 获取最大值和最小值的索引
max_index = s.idxmax()
min_index = s.idxmin()

# 其他属性和方法
print(s.dtype)   # 数据类型
print(s.shape)   # 形状
print(s.size)    # 元素个数
print(s.head())  # 前几个元素，默认是前 5 个
print(s.tail())  # 后几个元素，默认是后 5 个
print(s.sum())   # 求和
print(s.mean())  # 平均值
print(s.std())   # 标准差
print(s.min())   # 最小值
print(s.max())   # 最大值

print(s > 2)  # 返回一个布尔 Series，其中的元素值大于 2
print(s.dtype)  # 输出 Series 的数据类型
s = s.astype('float64')  # 将 Series 中的所有元素转换为 float64 类型


# https://www.runoob.com/pandas/pandas-dataframe.html
# DataFrame 特点：
# 二维结构： DataFrame 是一个二维表格，可以被看作是一个 Excel 电子表格或 SQL 表，具有行和列。可以将其视为多个 Series 对象组成的字典。
# 列的数据类型： 不同的列可以包含不同的数据类型，例如整数、浮点数、字符串或 Python 对象等。
# 索引：DataFrame 可以拥有行索引和列索引，类似于 Excel 中的行号和列标。
# 大小可变：可以添加和删除列，类似于 Python 中的字典。
# 自动对齐：在进行算术运算或数据对齐操作时，DataFrame 会自动对齐索引。
# 处理缺失数据：DataFrame 可以包含缺失数据，Pandas 使用 NaN（Not a Number）来表示。
# 数据操作：支持数据切片、索引、子集分割等操作。
# 时间序列支持：DataFrame 对时间序列数据有特别的支持，可以轻松地进行时间数据的切片、索引和操作。
# 丰富的数据访问功能：通过 .loc、.iloc 和 .query() 方法，可以灵活地访问和筛选数据。
# 灵活的数据处理功能：包括数据合并、重塑、透视、分组和聚合等。
# 数据可视化：虽然 DataFrame 本身不是可视化工具，但它可以与 Matplotlib 或 Seaborn 等可视化库结合使用，进行数据可视化。
# 高效的数据输入输出：可以方便地读取和写入数据，支持多种格式，如 CSV、Excel、SQL 数据库和 HDF5 格式。
# 描述性统计：提供了一系列方法来计算描述性统计数据，如 .describe()、.mean()、.sum() 等。
# 灵活的数据对齐和集成：可以轻松地与其他 DataFrame 或 Series 对象进行合并、连接或更新操作。
# 转换功能：可以对数据集中的值进行转换，例如使用 .apply() 方法应用自定义函数。
# 滚动窗口和时间序列分析：支持对数据集进行滚动窗口统计和时间序列分析。

# pandas.DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)

# 使用列表创建
import pandas as pd
data = [
        ['Google', 10],
        ['Runoob', 12],
        ['Wiki', 13]
]
# 创建DataFrame
df = pd.DataFrame(data, columns=['Site', 'Age'])
# 使用astype方法设置每列的数据类型
df['Site'] = df['Site'].astype(str)
df['Age'] = df['Age'].astype(float)
print(df)


# 使用字典创建
import pandas as pd
data = {
        'Site':['Google', 'Runoob', 'Wiki'],
        'Age':[10, 12, 13]
        }
df = pd.DataFrame(data)
print (df)


# 使用 ndarrays 创建
import numpy as np
import pandas as pd
# 创建一个包含网站和年龄的二维ndarray
ndarray_data = np.array([
    ['Google', 10],
    ['Runoob', 12],
    ['Wiki', 13]
])
# 使用DataFrame构造函数创建数据帧
df = pd.DataFrame(ndarray_data, columns=['Site', 'Age'])
# 打印数据帧
print(df)


# 使用字典创建  没有对应的部分数据为 NaN。
# Pandas 可以使用 loc 属性返回指定行的数据，如果没有设置索引，第一行索引为 0，第二行索引为 1，
import pandas as pd
data = [{'a': 1, 'b': 2},{'a': 5, 'b': 10, 'c': 20}]
df = pd.DataFrame(data)
print (df)



# Pandas 可以使用 loc 属性返回指定索 对应到某一行
import pandas as pd
data = {
  "calories": [420, 380, 390],
  "duration": [50, 40, 45]
}
df = pd.DataFrame(data, index = ["day1", "day2", "day3"])
# 指定索引
print(df.loc["day2"])


#
# 方法名称	功能描述
# head(n)	返回 DataFrame 的前 n 行数据（默认前 5 行）
# tail(n)	返回 DataFrame 的后 n 行数据（默认后 5 行）
# info()	显示 DataFrame 的简要信息，包括列名、数据类型、非空值数量等
# describe()	返回 DataFrame 数值列的统计信息，如均值、标准差、最小值等
# shape	返回 DataFrame 的行数和列数（行数, 列数）
# columns	返回 DataFrame 的所有列名
# index	返回 DataFrame 的行索引
# dtypes	返回每一列的数值数据类型
# sort_values(by)	按照指定列排序
# sort_index()	按行索引排序
# dropna()	删除含有缺失值（NaN）的行或列
# fillna(value)	用指定的值填充缺失值
# isnull()	判断缺失值，返回一个布尔值 DataFrame
# notnull()	判断非缺失值，返回一个布尔值 DataFrame
# loc[]	按标签索引选择数据
# iloc[]	按位置索引选择数据
# at[]	访问 DataFrame 中单个元素（比 loc[] 更高效）
# iat[]	访问 DataFrame 中单个元素（比 iloc[] 更高效）
# apply(func)	对 DataFrame 或 Series 应用一个函数
# applymap(func)	对 DataFrame 的每个元素应用函数（仅对 DataFrame）
# groupby(by)	分组操作，用于按某一列分组进行汇总统计
# pivot_table()	创建透视表
# merge()	合并多个 DataFrame（类似 SQL 的 JOIN 操作）
# concat()	按行或按列连接多个 DataFrame
# to_csv()	将 DataFrame 导出为 CSV 文件
# to_excel()	将 DataFrame 导出为 Excel 文件
# to_json()	将 DataFrame 导出为 JSON 格式
# to_sql()	将 DataFrame 导出为 SQL 数据库
# query()	使用 SQL 风格的语法查询 DataFrame
# duplicated()	返回布尔值 DataFrame，指示每行是否是重复的
# drop_duplicates()	删除重复的行
# set_index()	设置 DataFrame 的索引
# reset_index()	重置 DataFrame 的索引
# transpose()	转置 DataFrame（行列交换）


import pandas as pd

# 创建 DataFrame
data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'David'],
    'Age': [25, 30, 35, 40],
    'City': ['New York', 'Los Angeles', 'Chicago', 'Houston']
}
df = pd.DataFrame(data)

# 查看前两行数据
print(df.head(2))

# 查看 DataFrame 的基本信息
print(df.info())

# 获取描述统计信息
print(df.describe())

# 按年龄排序
df_sorted = df.sort_values(by='Age', ascending=False)
print(df_sorted)

# 选择指定列
print(df[['Name', 'Age']])

# 按索引选择行
print(df.iloc[1:3])  # 选择第二到第三行（按位置）

# 按标签选择行
print(df.loc[1:2])  # 选择第二到第三行（按标签）

# 计算分组统计（按城市分组，计算平均年龄）
print(df.groupby('City')['Age'].mean())

# 处理缺失值（填充缺失值）
df['Age'] = df['Age'].fillna(30)

# 导出为 CSV 文件
df.to_csv('output.csv', index=False)


# -------------------------------------------------

import pandas as pd

# 从字典创建：字典的键成为列名，值成为列数据。
# 通过字典创建 DataFrame
df = pd.DataFrame({'Column1': [1, 2, 3], 'Column2': [4, 5, 6]})

# 从列表的列表创建：外层列表代表行，内层列表代表列。
df = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]],
                  columns=['Column1', 'Column2', 'Column3'])

# 从 NumPy 数组创建：提供一个二维 NumPy 数组。.
import numpy as np
# 通过 NumPy 数组创建 DataFrame
df = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))

# 从 Series 创建 DataFrame：通过 pd.Series() 创建。
# 从 Series 创建 DataFrame
s1 = pd.Series(['Alice', 'Bob', 'Charlie'])
s2 = pd.Series([25, 30, 35])
s3 = pd.Series(['New York', 'Los Angeles', 'Chicago'])
df = pd.DataFrame({'Name': s1, 'Age': s2, 'City': s3})


# DataFrame 的属性和方法
print(df.shape)     # 形状
print(df.columns)   # 列名
print(df.index)     # 索引
print(df.head())    # 前几行数据，默认是前 5 行
print(df.tail())    # 后几行数据，默认是后 5 行
print(df.info())    # 数据信息
print(df.describe())# 描述统计信息
print(df.mean())    # 求平均值
print(df.sum())     # 求和

# 通过列名访问
print(df['Column1'])
# 通过属性访问
print(df.Name)
# 通过 .loc[] 访问
print(df.loc[:, 'Column1'])
# 通过 .iloc[] 访问
print(df.iloc[:, 0])  # 假设 'Column1' 是第一列
# 访问单个元素
print(df['Name'][0])

# 通过行标签访问
print(df.loc[0, 'Column1'])


# 修改列数据：直接对列进行赋值。
df['Column1'] = [10, 11, 12]

# 添加新列：给新列赋值。
df['NewColumn'] = [100, 200, 300]


# 使用 loc 为特定索引添加新行
df.loc[3] = [13, 14, 15, 16]
# 使用 append 添加新行到末尾
new_row = {'Column1': 13, 'Column2': 14, 'NewColumn': 16}
df = df.append(new_row, ignore_index=True)


# 使用concat添加新行
new_row = pd.DataFrame([[4, 7]], columns=['A', 'B'])  # 创建一个只包含新行的DataFrame
df = pd.concat([df, new_row], ignore_index=True)  # 将新行添加到原始DataFrame
print(df)


# 删除列：使用 drop 方法。
df_dropped = df.drop('Column1', axis=1)

# 删除行：同样使用 drop 方法。
df_dropped = df.drop(0)  # 删除索引为 0 的行

# DataFrame 的统计分析
# 描述性统计：使用 .describe() 查看数值列的统计摘要。

df.describe()
# 计算统计数据：使用聚合函数如 .sum()、.mean()、.max() 等。

df['Column1'].sum()
df.mean()
# DataFrame 的索引操作
# 重置索引：使用 .reset_index()

df_reset = df.reset_index(drop=True)
# 设置索引：使用 .set_index()。

df_set = df.set_index('Column1')
# DataFrame 的布尔索引
# 使用布尔表达式：根据条件过滤 DataFrame。

df[df['Column1'] > 2]
# DataFrame 的数据类型
# 查看数据类型：使用 dtypes 属性。

df.dtypes
# 转换数据类型：使用 astype 方法。

df['Column1'] = df['Column1'].astype('float64')
# DataFrame 的合并与分割
# 合并：使用 concat 或 merge 方法。

# 纵向合并
# pd.concat([df1, df2], ignore_index=True)

# 横向合并
# pd.merge(df1, df2, on='Column1')
# 分割：使用 pivot、melt 或自定义函数。

# 长格式转宽格式
df_pivot = df.pivot(index='Column1', columns='Column2', values='Column3')

# 宽格式转长格式
df_melt = df.melt(id_vars='Column1', value_vars=['Column2', 'Column3'])


# 索引和切片
print(df[['Name', 'Age']])  # 提取多列
print(df[1:3])               # 切片行
print(df.loc[:, 'Name'])     # 提取单列
print(df.loc[1:2, ['Name', 'Age']])  # 标签索引提取指定行列
print(df.iloc[:, 1:])        # 位置索引提取指定列


# # Pandas Excel 文件操作
# 读取 Excel 文件	pd.read_excel()	读取 Excel 文件，返回 DataFrame
# 将 DataFrame 写入 Excel	DataFrame.to_excel()	将 DataFrame 写入 Excel 文件
# 加载 Excel 文件	pd.ExcelFile()	加载 Excel 文件并访问多个表单
# 使用 ExcelWriter 写多个表单	pd.ExcelWriter()	写入多个 DataFrame 到同一 Excel 文件的不同表单

# Pandas 清洗空值
# # DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
# axis：默认为 0，表示逢空值剔除整行，如果设置参数 axis＝1 表示逢空值去掉整列。
# how：默认为 'any' 如果一行（或一列）里任何一个数据有出现 NA 就去掉整行，如果设置 how='all' 一行（或列）都是 NA 才去掉这整行。
# thresh：设置需要多少非空值的数据才可以保留下来的。
# subset：设置想要检查的列。如果是多个列，可以使用列名的 list 作为参数。
# inplace：如果设置 True，将计算得到的值直接覆盖之前的值并返回 None，修改的是源数据。



# 注意：默认情况下，dropna() 方法返回一个新的 DataFrame，不会修改源数据。
# 如果你要修改源数据 DataFrame, 可以使用 inplace = True 参数:
